package org.wisdom.security.config;

import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import org.wisdom.context.WisdomContextHolder;
import org.wisdom.security.dto.ValidatedToken;
import org.wisdom.security.exception.TokenNotValidException;
import org.wisdom.security.utils.TokenValidator;

import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Collections;

/**
 * token认证服务
 * 
 * @author zhangzhiyan
 * @date 2021/08/19 16:01
 **/
@Slf4j
@Component
public class TokenAuthenticationProvider implements AuthenticationProvider {

    private final TokenValidator tokenValidator;

    private final JwtSecurityProperties jwtSecurityProperties;

    public TokenAuthenticationProvider(JwtSecurityProperties jwtSecurityProperties) {
        Key key =
                new SecretKeySpec(jwtSecurityProperties.getTokenKey().getBytes(), SignatureAlgorithm.HS256.getJcaName());
        this.tokenValidator = new TokenValidator(key);
        this.jwtSecurityProperties = jwtSecurityProperties;
    }

    @Bean
    public TokenValidator tokenValidator() {
        return this.tokenValidator;
    }

    @Override
    public Authentication authenticate(Authentication authentication) {
        try {
            String authorizationHeader = authentication.getName();
            if(authorizationHeader.startsWith(this.jwtSecurityProperties.getTokenSchema())) {
                log.debug("开始token认证{}", authorizationHeader);
                String token = authorizationHeader.replace(this.jwtSecurityProperties.getTokenSchema(), "");
                ValidatedToken validatedToken = this.tokenValidator.validate(token);
                WisdomContextHolder.getContext().setUserId(validatedToken.getUserId());
                WisdomContextHolder.getContext().setUserName(validatedToken.getSubject());
                WisdomContextHolder.getContext().setToken(token);
                return new UsernamePasswordAuthenticationToken(validatedToken.getSubject(), null, Collections.emptyList());
            }
        } catch (TokenNotValidException e) {
            log.warn("Token 无效!", e);
        }
        return null;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
